/*
 *  $Id: FlyingStar.cs 1190 2010-11-12 15:02:56Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;

using AgateLib.InputLib;
using AgateLib.Geometry;

using Ragima.Helper;

namespace Ragima.Menu {
    class FlyingStar {
        private const int AlphaCycle1Speed = 15;
        private const int AlphaCycle2Speed = 500;
        private const int AlphaCycle1Size = 30;
        private const int AlphaCycle2Size = 225;

        private PointSource _source;
        private PointF _point, _target;
        private int _alpha;
        private int _a1, _a2;

        public FlyingStar(PointSource source) {
            _source = source;
            _point = _source.GetPoint();
            _a1 = Randomizer.Global.Next(AlphaCycle1Speed);
            _a2 = Randomizer.Global.Next(AlphaCycle2Speed);
            NewTarget();
        }

        public PointF Position {
            get { return _point; }
        }

        public void SetOffset(int diff) {
            float d = (float) diff * (255 - _alpha) / 204;
            SetOffset(ref _point, d);
            SetOffset(ref _target, d);
            _source.SetOffset(d);
        }

        public void Draw() {
            Data.LoadingBall.Color = Color.FromArgb(_alpha, Color.White);
            Data.LoadingBall.Draw(_point);
        }

        public void Process() {
            _a1++;
            if (_a1 == AlphaCycle1Speed) _a1 = 0;
            _a2++;
            if (_a2 == AlphaCycle2Speed) _a2 = 0;
            _alpha = GetSinus(_a1, AlphaCycle1Speed, AlphaCycle1Size) + GetSinus(_a2, AlphaCycle2Speed, AlphaCycle2Size);
            if (_point.ApproxEquals(_target)) NewTarget();
            double dx = _target.X - _point.X, dy = _target.Y - _point.Y;
            double length = Math.Sqrt(dx*dx + dy*dy);
            _point.X += (float) (dx / length / 10);
            _point.Y += (float) (dy / length / 10);
        }

        private void NewTarget() {
            _target = _source.GetAroundPoint();
        }

        private static int GetSinus(int x, int period, int ampl) {
            double y = Math.Sin(Math.PI * 2 * x / period);
            return (int) Math.Truncate((y+1)/2*ampl);
        }

        public static void SetOffset(ref PointF point, float d) {
            point.X += d;
            point.Y += d;
            if (d >= 0) {
                while (point.X >= Constants.DisplayWidth) point.X -= Constants.DisplayWidth;
                while (point.Y >= Constants.DisplayHeight) point.Y -= Constants.DisplayHeight;
            } else {
                while (point.X < 0) point.X += Constants.DisplayWidth;
                while (point.Y < 0) point.Y += Constants.DisplayHeight;
            }
        }
    }

    abstract class PointSource {
        public const int AroundRadius = 50;

        public abstract PointF GetPoint();

        public PointF GetAroundPoint() {
            PointF src = GetPoint();
            double alpha = Math.PI * 2 * Randomizer.Global.Next(1000) / 1000;
            float radius = Randomizer.Global.Next(AroundRadius / 3, AroundRadius);
            return new PointF(src.X + (float) Math.Cos(alpha) * radius,
                             src.Y + (float) Math.Sin(alpha) * radius);
        }

        public virtual void SetOffset(float d) {}
    }

    class StaticPointSource: PointSource {
        private PointF _point;

        public StaticPointSource(PointF point) {
            _point = point;
        }

        public override PointF GetPoint() {
            return _point;
        }

        public static StaticPointSource CreateRandom() {
            return new StaticPointSource(new PointF(Randomizer.Global.Next(Constants.DisplayWidth), Randomizer.Global.Next(Constants.DisplayHeight)));
        }

        public override void SetOffset(float d) {
            FlyingStar.SetOffset(ref _point, d);
        }
    }

    class SatellitePointSource: PointSource {
        private FlyingStar _star;

        public SatellitePointSource(FlyingStar star) {
            _star = star;
        }

        public override PointF GetPoint() {
            return _star.Position;
        }
    }

    class MousePointSource: PointSource {
        public MousePointSource() {}

        public override PointF GetPoint() {
            return new PointF(Mouse.Position.X, Mouse.Position.Y);
        }
    }
}